package com.uwlaser.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.uwlaser.config.FileProperties;
import com.uwlaser.domain.*;
import com.uwlaser.exception.BadRequestException;
import com.uwlaser.modules.system.service.RolesFactoryModelsService;
import com.uwlaser.service.FactoryTreePathInfoService;
import com.uwlaser.service.dto.FactoryTreePathInfoDto;
import com.uwlaser.service.mapper.*;
import com.uwlaser.utils.FileUtil;
import com.uwlaser.utils.StringUtils;
import com.uwlaser.utils.enums.DictValueEnum;
import lombok.AllArgsConstructor;
import com.uwlaser.base.PageInfo;
import com.uwlaser.base.QueryHelpMybatisPlus;
import com.uwlaser.base.impl.CommonServiceImpl;
import com.uwlaser.utils.ConvertUtil;
import com.uwlaser.utils.PageUtil;
import com.uwlaser.service.DeviceMainService;
import com.uwlaser.service.dto.DeviceMainDto;
import com.uwlaser.service.dto.DeviceMainQueryParam;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
// 默认不使用缓存
//import org.springframework.cache.annotation.CacheConfig;
//import org.springframework.cache.annotation.CacheEvict;
//import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author zk-Qin
* @date 2022-05-11
*/
@Service
@AllArgsConstructor
// @CacheConfig(cacheNames = DeviceMainService.CACHE_KEY)
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class DeviceMainServiceImpl extends CommonServiceImpl<DeviceMainMapper, DeviceMain> implements DeviceMainService {

    // private final RedisUtils redisUtils;
    private final DeviceMainMapper deviceMainMapper;

    private final FileProperties properties;

    private final DeviceFileMapper deviceFileMapper;

    private final FactoryModelMapper factoryModelMapper;

    public final FactoryTreePathInfoService factoryTreePathInfoService;

    private final RolesFactoryModelsService rolesFactoryModelsService;

    private final DeviceOnlineMapper deviceOnlineMapper;

    private final DeviceStatusMapper deviceStatusMapper;

    private final DeviceAlarmMapper deviceAlarmMapper;


    @Override
    public PageInfo<DeviceMainDto> queryAll(DeviceMainQueryParam query, Pageable pageable) {
        IPage<DeviceMain> queryPage = PageUtil.toMybatisPage(pageable);
        IPage<DeviceMain> page = deviceMainMapper.selectPage(queryPage, QueryHelpMybatisPlus.getPredicate(query));
        return ConvertUtil.convertPage(page, DeviceMainDto.class);
    }

    @Override
    public List<DeviceMainDto> queryAll(DeviceMainQueryParam query){
        return ConvertUtil.convertList(deviceMainMapper.selectList(QueryHelpMybatisPlus.getPredicate(query)), DeviceMainDto.class);
    }

    @Override
    public DeviceMain getById(Integer id) {
        return deviceMainMapper.selectById(id);
    }

    @Override
    // @Cacheable(key = "'id:' + #p0")
    public DeviceMainDto findById(Integer id) {
        return ConvertUtil.convert(getById(id), DeviceMainDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(DeviceMainDto resources) {
        DeviceMain entity = ConvertUtil.convert(resources, DeviceMain.class);
        return deviceMainMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateById(DeviceMainDto resources){
        DeviceMain entity = ConvertUtil.convert(resources, DeviceMain.class);
        int ret = deviceMainMapper.updateById(entity);
        // delCaches(resources.id);
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeByIds(Set<Integer> ids){

        List<DeviceMain> deviceMains = deviceMainMapper.selectBatchIds(ids);
        List<String> deviceCodes = deviceMains.stream().map(DeviceMain::getDeviceCode).collect(Collectors.toList());

        //删除工厂模型
        LambdaQueryWrapper<FactoryModel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FactoryModel :: getModelType ,DictValueEnum.MODEL_TYPE_DEVICE.getValue());
        queryWrapper.in(FactoryModel :: getModelCode,deviceCodes);
        List<FactoryModel> factoryModels = factoryModelMapper.selectList(queryWrapper);
        if(factoryModels != null && factoryModels.size() > 0){
            Set<Integer> modelIds = factoryModels.stream().map(FactoryModel::getId).collect(Collectors.toSet());
            //删除关系表数据
            factoryTreePathInfoService.removeByIds(modelIds);
            for (Integer id : modelIds){
                // 删除角色设备表关系
                rolesFactoryModelsService.removeFactoryModelId(id);
            }
            //删除模型表数据
            factoryModelMapper.delete(queryWrapper);
        }

        //删除文件
        LambdaQueryWrapper<DeviceFile> fileQueryWrapper = new LambdaQueryWrapper<>();
        fileQueryWrapper.in(DeviceFile :: getDeviceId,ids);
        List<DeviceFile> deviceFiles = deviceFileMapper.selectList(fileQueryWrapper);
        if(deviceFiles != null && deviceFiles.size() > 0){
            //删除文件
            for (DeviceFile deviceFile : deviceFiles) {
                //删除文件
                FileUtil.del(deviceFile.getDiskPath());
            }
        }
        //文件在数据库中删除
        deviceFileMapper.delete(fileQueryWrapper);

        // delCaches(ids);
        return deviceMainMapper.deleteBatchIds(ids);
    }

    /**
     * 添加
     * @param multipartFile
     * @param resources
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DeviceMainDto insert(MultipartFile multipartFile, DeviceMainDto resources) {
        DeviceMain entity = ConvertUtil.convert(resources, DeviceMain.class);
        //设置默认值
        entity.setIsOnline(DictValueEnum.DEVICE_OFF_LINE.getValue());
        entity.setDeviceStatus(DictValueEnum.DEVICE_STATUS_STOP.getValue());
        entity.setAlarmCode("");
        //设备编号去重
        DeviceMain deviceMain = new DeviceMain();
        deviceMain.setDeviceCode(entity.getDeviceCode());
        Integer integer = deviceMainMapper.selectCount(new QueryWrapper<>(deviceMain));
        if(integer > 0){
            throw new RuntimeException("设备编号【"+entity.getDeviceCode()+"】不能重复！");
        }
        //添加到工厂建模中
        addFactoryModel(entity);

        //添加设备列表
        deviceMainMapper.insert(entity);
        //处理图片
        if(multipartFile != null){
            DeviceFile deviceFile = saveImg(multipartFile, entity);
            resources.setPicture(deviceFile.getVisitPath());
            //更新图片字段
            DeviceMain update = new DeviceMain();
            update.setId(entity.getId());
            update.setPicture(deviceFile.getVisitPath());
            deviceMainMapper.updateById(update);
        }
        return resources;
    }

    /**
     * 更新
     * @param multipartFile
     * @param resources
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DeviceMainDto updateById(MultipartFile multipartFile, DeviceMainDto resources) {

        DeviceMain entity = ConvertUtil.convert(resources, DeviceMain.class);
        //旧的设备信息
        DeviceMain oldDevice = deviceMainMapper.selectById(resources.getId());

        deviceMainMapper.updateById(entity);

        DeviceMain deviceMain = new DeviceMain();
        deviceMain.setDeviceCode(entity.getDeviceCode());
        Integer integer = deviceMainMapper.selectCount(new QueryWrapper<>(deviceMain));
        if(integer >= 2){
            throw new RuntimeException("设备编号【"+entity.getDeviceCode()+"】不能重复！");
        }
        //更新工厂模型
        updateFactoryModel(oldDevice,entity);

        //删除图片
        if(multipartFile != null || StringUtils.isEmpty(entity.getPicture())){
            //判断设备图片是否存在
            DeviceFile deviceFile = new DeviceFile();
            deviceFile.setDeviceId(entity.getId());
            deviceFile.setAppType(DictValueEnum.DEVICE_FILE_TYPE_IMG.getValue());
            DeviceFile f = deviceFileMapper.selectOne(new QueryWrapper<>(deviceFile));
            if(f != null){
                deviceFileMapper.deleteById(f.getId());
                //删除文件
                FileUtil.del(f.getDiskPath());
                //更新图片字段
                DeviceMain update = new DeviceMain();
                update.setId(entity.getId());
                update.setPicture("");
                deviceMainMapper.updateById(update);
            }
        }
        //处理图片
        if(multipartFile != null){
            DeviceFile deviceFile = saveImg(multipartFile, entity);
            resources.setPicture(deviceFile.getVisitPath());
            //更新图片字段
            DeviceMain update = new DeviceMain();
            update.setId(entity.getId());
            update.setPicture(deviceFile.getVisitPath());
            deviceMainMapper.updateById(update);
        }

        return resources;
    }


    /**
     * 添加工厂建模
     * @param entity
     */
    private int addFactoryModel(DeviceMain entity) {

        FactoryModel stationModel = getStationModel(entity);

        FactoryModel factoryModel = new FactoryModel();
        factoryModel.setModelCode(entity.getDeviceCode());
        factoryModel.setModelName(entity.getDeviceName());
        factoryModel.setModelType(DictValueEnum.MODEL_TYPE_DEVICE.getValue());
        factoryModel.setPid(stationModel.getId());


        //查询所有父节点
        FactoryTreePathInfo factoryTreePathInfo = new FactoryTreePathInfo();
        factoryTreePathInfo.setDescendant(stationModel.getId());
        List<FactoryModel> factoryModels = factoryTreePathInfoService.queryAllFamily(factoryTreePathInfo);
        HashMap<String, FactoryModel> modelMap = new HashMap<>();
        for (FactoryModel model : factoryModels) {
            modelMap.put(model.getModelType(),model);
        }

        //位置
        entity.setPlace(
                modelMap.get(DictValueEnum.MODEL_TYPE_FACTROY.getValue()).getModelName()+ "/"
                + modelMap.get(DictValueEnum.MODEL_TYPE_WORKSHOP.getValue()).getModelName()+ "/"
                + modelMap.get(DictValueEnum.MODEL_TYPE_LINE.getValue()).getModelName() + "/"
                + modelMap.get(DictValueEnum.MODEL_TYPE_SECTION.getValue()).getModelName()+ "/"
                + modelMap.get(DictValueEnum.MODEL_TYPE_STATION.getValue()).getModelName()
        ) ;

        factoryModelMapper.insert(factoryModel);

        // 先往关系表加数据
        FactoryTreePathInfoDto treePathInfoDto = FactoryTreePathInfoDto.builder().id(factoryModel.getId()).ancestor(factoryModel.getPid()).build();;
        return factoryTreePathInfoService.insert(treePathInfoDto);
    }

    /**
     * 更新工厂模型
     * @param oldDevice
     * @param entity
     * @return
     */
    private int updateFactoryModel(DeviceMain oldDevice, DeviceMain entity) {
        //判断工位是否改变
        if(!oldDevice.getStationCode().equals(entity.getStationCode())){
            //删除原来了的设备模型
            FactoryModel factoryModel = new FactoryModel();
            factoryModel.setModelCode(oldDevice.getDeviceCode());
            factoryModel.setModelType(DictValueEnum.MODEL_TYPE_DEVICE.getValue());
            factoryModelMapper.delete(new QueryWrapper<>(factoryModel));
            //从新添加
            return addFactoryModel(entity);
        }

        //判断名称和编号改变
        if(!oldDevice.getDeviceCode().equals(entity.getDeviceCode()) || !oldDevice.getDeviceName().equals(entity.getDeviceName()) ){
            //更新内容
            FactoryModel factoryModel = new FactoryModel();
            factoryModel.setModelName(entity.getDeviceName());
            factoryModel.setModelCode(entity.getDeviceCode());

            //更新条件
            FactoryModel where = new FactoryModel();
            where.setModelCode(oldDevice.getDeviceCode());
            where.setModelType(DictValueEnum.MODEL_TYPE_DEVICE.getValue());
            return factoryModelMapper.update(factoryModel,new QueryWrapper<>(where));
        }

        return 0;
    }

    /**
     * 获取工厂模型工位
     * @return
     */
    public FactoryModel getStationModel(DeviceMain entity){
        //获取工段ID
        FactoryModel where = new FactoryModel();
        where.setModelCode(entity.getSectionCode());
        where.setModelType(DictValueEnum.MODEL_TYPE_SECTION.getValue());
        List<FactoryModel> factoryModels = factoryModelMapper.selectList(new QueryWrapper<>(where));
        if(factoryModels == null || factoryModels.size() == 0){
            throw new RuntimeException("获取工厂模型工段【"+entity.getSectionCode()+"】失败,没有发现！");
        }
        //获取工位ID
        LambdaQueryWrapper<FactoryModel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FactoryModel :: getModelType,DictValueEnum.MODEL_TYPE_STATION.getValue());
        wrapper.eq(FactoryModel :: getModelCode,entity.getStationCode());
        wrapper.in(FactoryModel :: getPid,factoryModels.stream().map(FactoryModel :: getId).collect(Collectors.toList()));
        FactoryModel station = factoryModelMapper.selectOne(wrapper);
        if(station == null){
            throw new RuntimeException("获取工厂模型工位【"+entity.getSectionCode()+"】失败,没有发现！");
        }
        return  station;
    }



    /**
     * 保存图片
     * @return
     */
    public DeviceFile saveImg(MultipartFile multipartFile, DeviceMain entity){
        // 文件大小验证
        FileUtil.checkSize(properties.getAvatarMaxSize(), multipartFile.getSize());
        // 验证文件上传的格式
        String image = "gif jpg png jpeg";
        String fileType = FileUtil.getExtensionName(multipartFile.getOriginalFilename());
        if(fileType != null && !image.contains(fileType)){
            throw new BadRequestException("文件格式错误！, 仅支持 " + image +" 格式");
        }

        String filePath = "imgs\\";
        File file = FileUtil.upload(multipartFile, properties.getPath().getDevice() + filePath);

        DeviceFile deviceFile = new DeviceFile();
        deviceFile.setDeviceId(entity.getId());
        deviceFile.setFileName(file.getName());
        deviceFile.setOriginalFileName(multipartFile.getOriginalFilename());
        deviceFile.setDiskPath(Objects.requireNonNull(file).getPath());
        deviceFile.setSuffix(fileType);
        deviceFile.setVisitPath("device\\" + filePath + file.getName());
        deviceFile.setAppType(DictValueEnum.DEVICE_FILE_TYPE_IMG.getValue());
        deviceFileMapper.insert(deviceFile);
        return deviceFile;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeById(Integer id){
        Set<Integer> set = new HashSet<>(1);
        set.add(id);
        return this.removeByIds(set);
    }

    @Override
    public PageInfo<DeviceMainDto> monitor(DeviceMainQueryParam query, Pageable pageable) {
        IPage<DeviceMain> queryPage = PageUtil.toMybatisPage(pageable);
        IPage<DeviceMain> page = deviceMainMapper.selectPage(queryPage, QueryHelpMybatisPlus.getPredicate(query));
        return ConvertUtil.convertPage(page, DeviceMainDto.class);
    }

    /*
    private void delCaches(Integer id) {
        redisUtils.delByKey(CACHE_KEY + "::id:", id);
    }

    private void delCaches(Set<Integer> ids) {
        for (Integer id: ids) {
            delCaches(id);
        }
    }*/

    /*
    @Override
    public void download(List<DeviceMainDto> all, HttpServletResponse response) throws IOException {
      List<Map<String, Object>> list = new ArrayList<>();
      for (DeviceMainDto deviceMain : all) {
        Map<String,Object> map = new LinkedHashMap<>();
              map.put("设备编码", deviceMain.getDeviceCode());
              map.put("设备名称", deviceMain.getDeviceName());
              map.put("设备类别", deviceMain.getDeviceType());
              map.put("设备型号", deviceMain.getDeviceModel());
              map.put("产线编码", deviceMain.getLineCode());
              map.put("工段编码", deviceMain.getSectionCode());
              map.put("工位代码", deviceMain.getStationCode());
              map.put("是否接收工单", deviceMain.getReceiveOrder());
              map.put("是否监控", deviceMain.getMonitor());
              map.put("描述", deviceMain.getRemark());
              map.put("创建人", deviceMain.getCreateBy());
              map.put("创建时间", deviceMain.getCreateTime());
              map.put("更新人", deviceMain.getUpdateBy());
              map.put("更新时间", deviceMain.getUpdateTime());
        list.add(map);
      }
      FileUtil.downloadExcel(list, response);
    }*/
}
